package utils

import (
	"bufio"
	"io"
	"io/ioutil"
	"mime/multipart"
	"os"
	"path/filepath"
	"sort"
	"strings"
)

type FileSort []os.DirEntry

func SaveFile(file multipart.File, path string) {
	dir := filepath.Dir(path)
	_ = os.MkdirAll(dir, os.ModePerm)
	newFile, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666) // os.O_TRUNC 覆盖写入
	defer func(newFile multipart.File) {
		_ = newFile.Close()
	}(newFile)

	wt := bufio.NewWriter(newFile)
	_, _ = file.Seek(0, io.SeekStart)
	_, _ = io.Copy(wt, file)
	_ = wt.Flush()
}

// IsFile false目录  ture文件
func IsFile(f string) bool {
	fi, e := os.Stat(f)
	if e != nil {
		return false
	}
	return !fi.IsDir()
}

// FileList 文件夹下的文件列表 不递归
func FileList(root string, onlyQueryFolder bool) (string, []os.DirEntry) {
	files, err := os.ReadDir(root)
	if err != nil {
		return root, []os.DirEntry{}
	}

	if onlyQueryFolder {
		var folders []os.DirEntry
		for _, file := range files {
			if file.IsDir() {
				folders = append(folders, file)
			}
		}
		files = folders
	}

	sort.Sort(FileSort(files))
	return root, files
}

func ReNameFile(root, oldFilePathName, newFilePathName string) bool {
	if !strings.Contains(oldFilePathName, root) || !strings.Contains(newFilePathName, root) {
		panic("非指定目录,不可进行操作")
	}

	if PathExists(newFilePathName) {
		panic("当前名称已存在")
	}
	err := os.Rename(oldFilePathName, newFilePathName)
	if err != nil {
		panic(err)
	}
	return true
}

func CopyFile(root, sourcePath, targetFolderPath string) bool {
	if !strings.Contains(sourcePath, root) || !strings.Contains(targetFolderPath, root) {
		panic("非指定目录,不可进行操作")
	}

	if !PathExists(sourcePath) {
		return false
	}

	dir := filepath.Dir(targetFolderPath)
	_ = os.MkdirAll(dir, os.ModePerm)

	info, _ := os.Lstat(sourcePath)

	targetFilePath := targetFolderPath + "/" + info.Name()
	targetFilePath = getTargetFilePathNoExit(targetFilePath, info.IsDir())
	_ = Copy(sourcePath, targetFilePath)

	return true
}

func MoveFile(root, sourcePath, targetFolderPath string) bool {
	if !strings.Contains(sourcePath, root) || !strings.Contains(targetFolderPath, root) {
		panic("非指定目录,不可进行操作")
	}

	err := os.Rename(sourcePath, targetFolderPath)
	if err != nil {
		panic(err)
	}
	return err == nil
}

func CreateFolder(folderPath string) bool {
	folderPath = getTargetFilePathNoExit(folderPath, true)
	err := os.MkdirAll(folderPath, os.ModePerm)
	if err != nil {
		panic(err)
	}
	return err == nil
}

func DeleteFile(root, filePath string) bool {
	if !strings.Contains(filePath, root) {
		panic("非指定目录,不可进行操作")
	}
	err := os.Remove(filePath)
	if err != nil {
		panic(err)
	}
	return err == nil
}

// getTargetFilePathNoExit 返回一个不存在的名称
func getTargetFilePathNoExit(targetFilePath string, isDirectory bool) string {
	if PathExists(targetFilePath) {
		file, _ := os.Lstat(targetFilePath)
		if isDirectory {
			targetFilePath = targetFilePath + "(1)"
			return getTargetFilePathNoExit(targetFilePath, isDirectory)
		} else {
			split := strings.Split(file.Name(), ".")
			targetFilePath = strings.ReplaceAll(targetFilePath, "."+split[1], "(1)."+split[1])
			return getTargetFilePathNoExit(targetFilePath, isDirectory)
		}
	} else {
		return targetFilePath
	}
}

func PathExists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return false
}

// Copy 复制整个文件夹或单个文件
func Copy(from, to string) error {
	f, e := os.Stat(from)
	if e != nil {
		return e
	}

	if f.IsDir() {
		//from是文件夹，那么定义to也是文件夹
		if list, e := ioutil.ReadDir(from); e == nil {
			for _, item := range list {
				if e = Copy(filepath.Join(from, item.Name()), filepath.Join(to, item.Name())); e != nil {
					return e
				}
			}
		}
	} else {
		//from是文件，那么创建to的文件夹
		p := filepath.Dir(to)
		if _, e = os.Stat(p); e != nil {
			if e = os.MkdirAll(p, 0777); e != nil {
				return e
			}
		}

		//读取源文件
		file, e := os.Open(from)
		if e != nil {
			return e
		}
		defer file.Close()
		bufReader := bufio.NewReader(file)
		// 创建一个文件用于保存
		out, e := os.Create(to)
		if e != nil {
			return e
		}
		defer out.Close()
		// 然后将文件流和文件流对接起来
		_, e = io.Copy(out, bufReader)
	}
	return e
}

// Len 返回传入数据的总数
func (s FileSort) Len() int {
	return len(s)
}

// Less 按字段比较大小,此处是降序排序， 返回数组中下标为i的数据是否小于下标为j的数据
func (s FileSort) Less(i, j int) bool {
	return s[i].IsDir()
}

// Swap 两个对象满足Less()则位置对换,表示执行交换数组中下标为i的数据和下标为j的数据
func (s FileSort) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}
